package xyz.gpgl.erp.logic.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Sets;
import common.util.base.CommonUtil;
import common.util.base.CustomizeRuntimeException;
import common.util.mybatis.plus.layui.Page;
import common.util.mybatis.plus.logic.LogicBaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import xyz.gpgl.erp.logic.entity.LogicEmailInfo;
import xyz.gpgl.erp.logic.entity.LogicShares;
import xyz.gpgl.erp.logic.entity.LogicSharesEmail;
import xyz.gpgl.erp.logic.entity.LogicSharesPrice;
import xyz.gpgl.erp.logic.entity.dto.LogicSharesPageDto;
import xyz.gpgl.erp.logic.entity.emeus.LogicEmailInfoEmeus;
import xyz.gpgl.erp.logic.entity.emeus.LogicSharesEmailEmeus;
import xyz.gpgl.erp.logic.entity.emeus.LogicSharesEmeus;
import xyz.gpgl.erp.logic.entity.emeus.LogicSharesPriceEmeus;
import xyz.gpgl.erp.logic.entity.param.LogicSharesImportParam;
import xyz.gpgl.erp.logic.entity.param.LogicSharesListDataParam;
import xyz.gpgl.erp.logic.entity.param.LogicSharesParam;
import xyz.gpgl.erp.logic.mapper.LogicSharesMapper;
import xyz.gpgl.erp.logic.service.*;
import xyz.gpgl.erp.sys.entity.SysUser;
import xyz.gpgl.erp.sys.entity.emeus.SysUserEmeus;
import xyz.gpgl.erp.sys.service.ISysUserService;
import xyz.gpgl.erp.sys.service.impl.MyUserDetailServiceImpl;

import java.beans.Transient;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 股票信息 服务实现类
 * </p>
 *
 * @author liubo
 * @since 2020-11-01
 */
@Slf4j
@Service
public class LogicSharesServiceImpl extends LogicBaseServiceImpl<LogicSharesMapper, LogicShares> implements ILogicSharesService {

    @Autowired
    private ILogicSharesEmailService logicSharesEmailService;
    @Autowired
    private ILogicEmailInfoService logicEmailInfoService;
    @Autowired
    private IEmailService emailService;
    @Autowired
    private ILogicSharesPriceService logicSharesPriceService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ILogicSharesService logicSharesService;

    /**深证*/
    private static final Set<String> sz = Sets.newHashSet("000","001","002","200","300");
    /**上证*/
    private static final Set<String> sh = Sets.newHashSet("600","601","603","900");

    @Override
    @Transient
    public void saveSharesInfo(LogicSharesParam param) {
        LogicShares entity = CommonUtil.copyBean(param, LogicShares.class);
        entity.setStockExchange(null);
        sz.stream().forEach(code->{
            if(entity.getCode().startsWith(code)){
                entity.setStockExchange(LogicSharesEmeus.StockExchange.shenzheng);
                return;
            }
        });
        sh.stream().forEach(code->{
            if(entity.getCode().startsWith(code)){
                entity.setStockExchange(LogicSharesEmeus.StockExchange.shangzheng);
                return;
            }
        });
        if(CommonUtil.isEmpty(entity.getStockExchange())){
            throw new RuntimeException("未定义的股票编码");
        }
        this.saveOrUpdate(entity);
        MyUserDetailServiceImpl.MyUserDetails user = (MyUserDetailServiceImpl.MyUserDetails) SecurityContextHolder
                .getContext().getAuthentication().getPrincipal();
        if (CommonUtil.isNotEmpty(param.getEmails())){
            QueryWrapper query = new QueryWrapper();
            query.eq(LogicSharesEmailEmeus.sharesId,entity.getId());
            this.logicSharesEmailService.remove(query );
            for (LogicEmailInfo email : param.getEmails()) {
                LogicSharesEmail se = new LogicSharesEmail();
                se.setEmailId(email.getId());
                se.setSharesId(entity.getId());
                se.setUsername(user.getUsername());
                this.logicSharesEmailService.save(se);

                UpdateWrapper<LogicSharesPrice> update = new UpdateWrapper<>();
                update.eq(LogicSharesPriceEmeus.sharesId,entity.getId());
                update.eq(LogicSharesPriceEmeus.username,user.getUsername());
                this.logicSharesPriceService.remove(update);

                LogicSharesPrice price = new LogicSharesPrice();
                price.setBuyPrice(param.getBuyPrice());
                price.setSellPrice(param.getSellPrice());
                price.setSharesId(entity.getId());
                price.setUsername(user.getUsername());
                this.logicSharesPriceService.save(price);
            }
        }

    }

    @Override
    public Page<LogicEmailInfo> userEmail(Integer id, Page<LogicEmailInfo> page) {
        MyUserDetailServiceImpl.MyUserDetails user = (MyUserDetailServiceImpl.MyUserDetails) SecurityContextHolder
                .getContext().getAuthentication().getPrincipal();
        QueryWrapper<LogicSharesEmail> queryWrapper = new QueryWrapper();
        queryWrapper.eq(LogicSharesEmailEmeus.sharesId,id);
        queryWrapper.eq(LogicSharesEmailEmeus.username,user.getUsername());
        List<LogicSharesEmail> list = this.logicSharesEmailService.list(queryWrapper);
        if (CommonUtil.isEmpty(list)) {
            return page;
        }
        Set<Integer> sharesIds = list.stream().map(e -> e.getEmailId()).collect(Collectors.toSet());
        QueryWrapper<LogicEmailInfo> query= new QueryWrapper<>();
        query.in(LogicEmailInfoEmeus.id,sharesIds);
        this.logicEmailInfoService.page(page, query);
        return page;
    }

    @Override
    public Page listData(LogicSharesListDataParam param, Page page) {
        QueryWrapper<LogicShares> query = new QueryWrapper<>();
        query.like(CommonUtil.isNotEmpty(param.getCode()),LogicSharesEmeus.code,param.getCode());
        query.like(CommonUtil.isNotEmpty(param.getName()),LogicSharesEmeus.name,param.getName());
        query.eq(CommonUtil.isNotEmpty(param.getDoubleSales()),LogicSharesEmeus.doubleSales,param.getDoubleSales());
        page = this.page(page, query);
        if(CommonUtil.isNotEmpty(page.getRecords())){
            List<LogicSharesPageDto> list = new ArrayList<>();
            MyUserDetailServiceImpl.MyUserDetails user = (MyUserDetailServiceImpl.MyUserDetails) SecurityContextHolder
                        .getContext().getAuthentication().getPrincipal();
            Set<Integer> ids = new HashSet<>();
            page.getRecords().forEach(e->{
                ids.add(((LogicShares)e).getId());
            });
            QueryWrapper<LogicSharesPrice> priceQuery = new QueryWrapper<>();
            priceQuery.eq(LogicSharesPriceEmeus.username,user.getUsername());
            priceQuery.in(LogicSharesPriceEmeus.sharesId,ids);
            List<LogicSharesPrice> prices = this.logicSharesPriceService.list(priceQuery);
            Map<Integer,LogicSharesPrice> priceMap = new HashMap<>();
            if (CommonUtil.isNotEmpty(prices)){
                prices.forEach(e->priceMap.put(e.getSharesId(),e));
            }
            for (Object record : page.getRecords()) {
                LogicSharesPageDto dto = CommonUtil.copyBean(record, LogicSharesPageDto.class);
                LogicSharesPrice price = priceMap.get(dto.getId());
                if (CommonUtil.isEmpty(price)){
                    dto.setBuyPrice(BigDecimal.ZERO);
                    dto.setSellPrice(BigDecimal.ZERO);
                }else {
                    dto.setBuyPrice(price.getBuyPrice());
                    dto.setSellPrice(price.getSellPrice());
                }
                list.add(dto);
            }
            page.setRecords(list);
        }
        return page;
    }
    /**
     * 日期 , 股票, 帐号, 价格
     */
    private static Map<String,Map<String,Map<String,BigDecimal>>> sendMap = new HashMap<>();
    @Override
    public void stockPriceScanning(List<LogicShares> list) {
        if (CommonUtil.isNotEmpty(list)){
            String dayKey = CommonUtil.getCurrentDateTimeByFormat("yyyyMMdd");
            Map<String, Map<String, BigDecimal>> sharesMap = sendMap.get(dayKey);
            if(CommonUtil.isEmpty(sharesMap)){
                sharesMap = new HashMap<>();
                //重新初始化一个Map
                sendMap = new HashMap<>();
                sendMap.put(dayKey,sharesMap);
            }

            Map<String, SysUser> sendUserMap = new HashMap<>();
            List<LogicSharesPrice> sharesPrices = logicSharesPriceService.queryInBatch(
                    list.stream().map(e -> e.getId()).collect(Collectors.toList()),
                    LogicSharesPriceEmeus.sharesId,100);


            Map<Integer,List<LogicSharesPrice>> priceMap = new HashMap<>();
            if (CommonUtil.isNotEmpty(sharesPrices)){
                sharesPrices.forEach(e->{
                    List<LogicSharesPrice> price = priceMap.get(e.getSharesId());
                    if (CommonUtil.isEmpty(price)){
                        price = new ArrayList<>();
                    }
                    price.add(e);
                    priceMap.put(e.getSharesId(),price);
                });
            }
            Map<String,String> sendMap = new HashMap<>();
            for (LogicShares shares : list) {
                //设定购买价大于0 并且当前价格大于0
                List<LogicSharesPrice> priceList = priceMap.get(shares.getId());
                if (CommonUtil.isEmpty(priceList)){
                    continue;
                }
                for (LogicSharesPrice price : priceList) {
                    if(price.getBuyPrice().compareTo(BigDecimal.ZERO)>0&&
                            shares.getCurrentPrice().compareTo(BigDecimal.ZERO)>0){
                        //触发价格
                        BigDecimal triggerPrice = price.getBuyPrice().multiply(new BigDecimal(1));
                        ///BigDecimal triggerPrice = price.getBuyPrice().multiply(new BigDecimal(1.1));
                        // 当触发价 小于设定购买价格后执行
                        if(triggerPrice.compareTo(shares.getCurrentPrice())>0) {
                            System.err.println(String.format( " code:%s name:%s priceID:%s  buy:%s",shares.getCode(),shares.getName(),price.getId(),price.getBuyPrice()));
                            Map<String, BigDecimal> accountMap = sharesMap.get(shares.getCode());
                            if (CommonUtil.isEmpty(accountMap)) {
                                accountMap = new HashMap<>();
                                sharesMap.put(shares.getCode(),accountMap);
                            }
                            QueryWrapper<LogicSharesEmail> query = new QueryWrapper<>();
                            query.select(LogicSharesEmailEmeus.emailId);
                            query.eq(LogicSharesEmailEmeus.sharesId,shares.getId());
                            query.eq(LogicSharesEmailEmeus.username,price.getUsername());
                            List<LogicSharesEmail> emailsIdList = this.logicSharesEmailService.list(query);
                            if(CommonUtil.isEmpty(emailsIdList)){
                                //当前账号不存在 发送账号,不放松,不记录
                                continue;
                            }
                            Set<Integer> emailsIds = emailsIdList.stream().map(e -> e.getEmailId()).collect(Collectors.toSet());
                            List<LogicEmailInfo> emailInfos = this.logicEmailInfoService.listByIds(emailsIds);
                            if (CommonUtil.isNotEmpty(emailInfos)){
                                for (LogicEmailInfo email : emailInfos) {
                                    BigDecimal nextPrice = accountMap.get(email.getEmail());
                                    if (CommonUtil.isNotEmpty(nextPrice)
                                            &&shares.getCurrentPrice().compareTo(nextPrice)>=0){
                                        //当存在 价格已存在,并且上次保存价格大于等于当前价格,不在重新发送
                                        continue;
                                    }
                                    accountMap.put(email.getEmail(),shares.getCurrentPrice());
                                    String msg = sendMap.get(email.getEmail());
                                    if (CommonUtil.isNotEmpty(msg)){
                                        msg = msg + "\r\n";
                                    }else{
                                        msg = StringUtils.EMPTY;
                                    }
                                    SysUser sysUser = sendUserMap.get(price.getUsername());
                                    if (CommonUtil.isEmpty(sysUser)){
                                        QueryWrapper<SysUser> userQuery = new QueryWrapper<>();
                                        userQuery.eq(SysUserEmeus.phone, price.getUsername());
                                        sysUser = this.sysUserService.getOne(userQuery);
                                    }
                                    sendMap.put(email.getEmail(),
                                            String.format("[%s]%s%s[%s]购买提醒,设定购买价: %s,当前购买价: %s,幅度: %s %%,已触发购买条件,设定人: %s"
                                                    ,CommonUtil.getCurrentDateTime(),msg,shares.getName(),shares.getCode(),
                                                    price.getBuyPrice().setScale(2,BigDecimal.ROUND_HALF_UP),
                                                    shares.getCurrentPrice().setScale(2,BigDecimal.ROUND_HALF_UP),
                                                    price.getBuyPrice().subtract(shares.getCurrentPrice())
                                                            .divide(price.getBuyPrice(),2,BigDecimal.ROUND_HALF_UP)
                                                            .multiply(new BigDecimal(100)),
                                                    sysUser.getName()

                                            )
                                    );
                                }
                            }
                        }
                    }
                }
            }
            for (String account : sendMap.keySet()) {
                log.info(String.format("%s:%s",account,sendMap.get(account)));
                emailService.sendSimpleMail(account,"购买提醒",sendMap.get(account));
            }

        }
    }

    /**
     * 文件导入
     *
     * @param file
     */
    @Override
    public void importShares(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(), new AnalysisEventListener() {
                private List<LinkedHashMap<Integer,String>> rows = new ArrayList<>();
                @Override
                public void invoke(Object data, AnalysisContext context) {
                    rows.add((LinkedHashMap<Integer, String>) data);
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    MyUserDetailServiceImpl.MyUserDetails user = (MyUserDetailServiceImpl.MyUserDetails) SecurityContextHolder
                            .getContext().getAuthentication().getPrincipal();
                    List<Field> fieldList = CommonUtil.getFieldList(LogicSharesImportParam.class);
                    for (int i = 0; i < rows.size(); i++) {
                        LogicSharesImportParam param = new LogicSharesImportParam();
                        for (int j = 0; j < fieldList.size(); j++) {
                            Field field = fieldList.get(j);
                            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                            Integer index = annotation.index();
                            if(index == -1){
                                index = j;
                            }
                            String value = rows.get(i).get(index);
                            try {
                                field.setAccessible(true);
                                if (field.getType().equals(String.class)){
                                    field.set(param,value);
                                }else if (field.getType().equals(Integer.class)){
                                    field.set(param,Integer.valueOf(value));
                                }else if (field.getType().equals(Long.class)){
                                    field.set(param,Long.valueOf(value));
                                }else if (field.getType().equals(Double.class)){
                                    field.set(param,Double.valueOf(value));
                                }else if (field.getType().equals(BigDecimal.class)){
                                    field.set(param,new BigDecimal(value));
                                }
                            } catch (IllegalAccessException e) {
                                String type = ",必须为数字";
                                if(field.getType().isAssignableFrom(Number.class)){
                                    type =",必须为数字";
                                }
                                throw new CustomizeRuntimeException("第"+(i+1)+"行"+(j+1)+"列数据个数错误"+type);
                            }

                        }

                        QueryWrapper<LogicShares> query = new QueryWrapper<>();
                        query.eq(LogicSharesEmeus.code,param.getCode());
                        LogicShares one = logicSharesService.getOne(query);
                        if (CommonUtil.isNotEmpty(one)){
                            QueryWrapper<LogicSharesPrice> wrapper = new QueryWrapper<>();
                            wrapper.eq(LogicSharesPriceEmeus.sharesId,one.getId());
                            wrapper.eq(LogicSharesPriceEmeus.username,user.getUsername());
                            LogicSharesPrice price = logicSharesPriceService.getOne(wrapper);
                            if (CommonUtil.isEmpty(price)){
                                price = new LogicSharesPrice();
                                price.setBuyPrice(param.getBuyPrice());
                                price.setSharesId(one.getId());
                                price.setSellPrice(BigDecimal.ZERO);
                                price.setUsername(user.getUsername());
                                logicSharesPriceService.save(price);
                            }else{
                                UpdateWrapper<LogicSharesPrice> updateWrapper = new UpdateWrapper<>();
                                updateWrapper.set(LogicSharesPriceEmeus.buyPrice,param.getBuyPrice());
                                updateWrapper.eq(LogicSharesPriceEmeus.id,price.getId());
                                logicSharesPriceService.update(updateWrapper);
                            }
                        }else{
                            LogicShares shares= CommonUtil.copyBean(param,LogicShares.class);
                            sz.stream().forEach(code->{
                                if(shares.getCode().startsWith(code)){
                                    shares.setStockExchange(LogicSharesEmeus.StockExchange.shenzheng);
                                    return;
                                }
                            });
                            sh.stream().forEach(code->{
                                if(shares.getCode().startsWith(code)){
                                      shares.setStockExchange(LogicSharesEmeus.StockExchange.shangzheng);
                                    return;
                                }
                            });
                            log.error(CommonUtil.convertObjectToJson(shares));
                            logicSharesService.save(shares);

                            LogicSharesPrice price = new LogicSharesPrice();
                            price.setBuyPrice(param.getBuyPrice());
                            price.setSharesId(shares.getId());
                            price.setSellPrice(BigDecimal.ZERO);
                            price.setUsername(user.getUsername());
                            logicSharesPriceService.save(price);
                        }
                    }

                }
            }).sheet().headRowNumber(0).doRead();
        } catch (IOException e) {
            log.error("导入错误",e);
        }
    }
}
